#include "hdtrackingwindow.h"

#include <QTime>
#include <QFile>
#include <QDataStream>
#include <QtGui>
#include <QMessageBox>
#include <QProcess>

#include "hdcamera.h"
#include "hdcamerarenderer.h"
#include "hdcameracalibration.h"
#include "hdpointsunprojection.h"
#include "testwindow.h"
#include "hdpushbuttons.h"
#include "hdcontroller.h"

QList<HDCamera*>			cameras;
QList<HDCameraRenderer*>	viewers;
QList<HDController*>		controllers;

HDCameraCalibration			*calib;
HDPointsUnprojection		*unproj;

QSemaphore					*calibrationFinished;
QSemaphore					*unprojectionReady;

QList<QSemaphore*>			captureReady;
QList<QSemaphore*>			captureFinished;

int							camerasCount = 0;
int							markersCount = 0;

int							currentCameraIndex = -1;
int							currentObjectIndex = -1;

bool						bCalibrate = false;
bool						bSnap = false;
bool						bRectify = false;

HDPushButtons				*pushButtons;
TestWindow					*w;
QProcess					*myProcess;


HDTrackingWindow::HDTrackingWindow(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
	ui.setupUi(this);
	adjustSize();

// 	pushButtons = new HDPushButtons(this);
// 	connect(pushButtons, SIGNAL(LeftThumbToggled(bool)), this, SLOT(on_pushButtons_LeftThumbToggled(bool)));
// 	connect(pushButtons, SIGNAL(RightThumbToggled(bool)), this, SLOT(on_pushButtons_RightThumbToggled(bool)));
// 	connect(pushButtons, SIGNAL(LeftIndexToggled(bool)), this, SLOT(on_pushButtons_LeftIndexToggled(bool)));
// 	connect(pushButtons, SIGNAL(RightIndexToggled(bool)), this, SLOT(on_pushButtons_RightIndexToggled(bool)));
// 	connect(pushButtons, SIGNAL(LeftMiddleToggled(bool)), this, SLOT(on_pushButtons_LeftMiddleToggled(bool)));
// 	connect(pushButtons, SIGNAL(RightMiddleToggled(bool)), this, SLOT(on_pushButtons_RightMiddleToggled(bool)));
// 	connect(pushButtons, SIGNAL(LeftRingToggled(bool)), this, SLOT(on_pushButtons_LeftRingToggled(bool)));
// 	connect(pushButtons, SIGNAL(RightRingToggled(bool)), this, SLOT(on_pushButtons_RightRingToggled(bool)));
}

HDTrackingWindow::~HDTrackingWindow()
{
	foreach (HDCamera* camera, cameras)
	{
		camera->ReleaseCapture();
	}

// 	if(myProcess)
// 	{
// 		myProcess->kill();
// 		delete myProcess;
// 	}
}

/************************************************************************/
/*                                                                      */
/************************************************************************/
void HDTrackingWindow::on_cmbObjects_currentIndexChanged(int newIndex)
{
	currentObjectIndex = newIndex;

	ui.chkEnableHue->setChecked(viewers[currentCameraIndex]->selectedMarker()->rangeHue());
	ui.chkEnableSat->setChecked(viewers[currentCameraIndex]->selectedMarker()->rangeSat());
	ui.chkEnableVal->setChecked(viewers[currentCameraIndex]->selectedMarker()->rangeVal());

	ui.sldMinHue->setValue(viewers[currentCameraIndex]->selectedMarker()->minHue());
	ui.sldMaxHue->setValue(viewers[currentCameraIndex]->selectedMarker()->maxHue());
	ui.sldMinSaturation->setValue(viewers[currentCameraIndex]->selectedMarker()->minSaturation() * 255.0f);
	ui.sldMaxSaturation->setValue(viewers[currentCameraIndex]->selectedMarker()->maxSaturation() * 255.0f);
	ui.sldMinValue->setValue(viewers[currentCameraIndex]->selectedMarker()->minValue() * 255.0f);
	ui.sldMaxValue->setValue(viewers[currentCameraIndex]->selectedMarker()->maxValue() * 255.0f);

	ui.btnBackProj->setChecked(viewers[currentCameraIndex]->backProjection());

	viewers[currentCameraIndex]->updateHistogramPanels();
}

void HDTrackingWindow::viewers_onFocusChanged(int index)
{
	currentCameraIndex = index;

	if(ui.cmbObjects->count() > 0)
		on_cmbObjects_currentIndexChanged(ui.cmbObjects->currentIndex());
}
void HDTrackingWindow::onCalibrationFinished()
{
	ui.btnCalibrate->toggle();
	ui.chkRectify->setEnabled(true);
}

void HDTrackingWindow::onNew3DPointCalculated(float x, float y, float z)
{
	/*QString coord = QString::fromAscii("(");
	coord.append(QString("%1").arg((int)x,5));
	coord.append(" , ");
	coord.append(QString("%1").arg((int)y,5));
	coord.append(" , ");
	coord.append(QString("%1").arg((int)z,5));
	coord.append(" ) ");*/

	QString coord = QString("{%1, %2, %3}")
		.arg((int)controllers[0]->position()->x)
		.arg((int)controllers[0]->position()->y)
		.arg((int)controllers[0]->position()->z);

	ui.textBoxCoords->setText(coord);

// 	if(w)
// 	{
// 		w->UpdateToolLocation(x, y, z);
// 	}
}

/************************************************************************/
/* Buttons Slots.                                                       */
/************************************************************************/
void HDTrackingWindow::on_btnCapture_clicked()
{
	ui.btnCapture->setEnabled(false);
	ui.nudNoOfCameras->setEnabled(false);
	this->repaint();

	camerasCount = ui.nudNoOfCameras->value();

	QHBoxLayout* hLayout = new QHBoxLayout;

	// Settings per Camera.
	for (int i = 0; i < camerasCount; i++)
	{
		// Add new HDCameraRenderer Controls.
		viewers.append(new HDCameraRenderer(this, i));
		viewers[i]->setMinimumSize(320, 240);
		connect(viewers[i], SIGNAL(focusChanged(int)), this, SLOT(viewers_onFocusChanged(int)));
		hLayout->addWidget(viewers[i]);

		// Add new HDCamera Objects.
		cameras.append(new HDCamera(this, FPS, FRAME_WIDTH, FRAME_HEIGHT));
		cameras[i]->Initialize(i);
		//cameras[i]->StartCapture();


		// Semaphores
		captureReady.append(new QSemaphore(1));
		captureFinished.append(new QSemaphore(0));
	}

	currentCameraIndex = 0;

	calibrationFinished = new QSemaphore(0);
	unprojectionReady = new QSemaphore(0);

	//calib = new HDCameraCalibration(this);
	unproj = new HDPointsUnprojection(this);

	//connect(calib, SIGNAL(CalibrationFinished()), this, SLOT(onCalibrationFinished()));
	connect(unproj,SIGNAL(New3DCoordinateCalculated(float,float,float)),this, SLOT(onNew3DPointCalculated(float,float,float)));
	ui.verticalLayout->addLayout(hLayout);

	ui.btnAddObject->setEnabled(true);
	ui.btnCalibrate->setEnabled(true);

	//TODO: REMOVE THIS
// 	calib->LoadRectificationMaps("c:\\zerox.hd","c:\\zeroy.hd","c:\\onex.hd","c:\\oney.hd","c:\\unproject.hd");
// 	ui.chkRectify->setEnabled(true);
}

void HDTrackingWindow::on_btnCalibrate_toggled(bool enable)
{
	bCalibrate = enable;
	ui.btnSnap->setEnabled(enable);
}
void HDTrackingWindow::on_btnHideWindow_clicked()
{
	this->hide();
}

void HDTrackingWindow::on_btnBackProj_clicked(bool enable)
{
	viewers[currentCameraIndex]->setBackProjection(enable);
}

void HDTrackingWindow::on_btnAddObject_clicked()
{
	controllers.append(new HDController(this, viewers[0]->objectMarkers.count()));

	for (int i = 0; i < camerasCount; i++)
	{
		viewers[i]->addMarker();
	}

	ui.cmbObjects->addItem(tr("Object %1").arg(ui.cmbObjects->count() + 1), 0);
	ui.cmbObjects->setCurrentIndex(ui.cmbObjects->count()-1);


	ui.chkEnableHue->setEnabled(true);
	ui.chkEnableSat->setEnabled(true);
	ui.chkEnableVal->setEnabled(true);

	ui.btnHideWindow->setEnabled(true);
	ui.btnToggleDemo->setEnabled(true);

	ui.cmbDemos->setEnabled(true);
	ui.btnBackProj->setEnabled(true);
	ui.cmbObjects->setEnabled(true);
}

void HDTrackingWindow::on_btnSnap_clicked()
{
	bSnap = true;
}

void HDTrackingWindow::on_btnToggleDemo_toggled(bool enable)
{
	if(enable)
	{
		viewers[currentCameraIndex]->setDemoID((HDDemoID)ui.cmbDemos->currentIndex());
		ui.btnToggleDemo->setText(tr("Stop Demo"));
	}
	else
	{
		viewers[currentCameraIndex]->setDemoID(DEMO_NONE);
		ui.btnToggleDemo->setText(tr("Start Demo"));
	}

	ui.cmbDemos->setEnabled(!enable);
}

void HDTrackingWindow::on_btnStart3DWorld_clicked()
{
	QString program = QApplication::applicationFilePath();
	QStringList arguments;
	arguments << "deformation";

	myProcess = new QProcess();
	myProcess->start(program, arguments);
}

/************************************************************************/
/* CheckBoxs Event Handlers.                                            */
/************************************************************************/
void HDTrackingWindow::on_chkRectify_stateChanged(int enable)
{
	bRectify = enable;
}

void HDTrackingWindow::on_chkEnableHue_stateChanged(int enable)
{
	viewers[currentCameraIndex]->selectedMarker()->enableRangeHue(enable);

	ui.sldMinHue->setEnabled(enable);
	ui.sldMaxHue->setEnabled(enable);
}

void HDTrackingWindow::on_chkEnableSat_stateChanged(int enable)
{
	viewers[currentCameraIndex]->selectedMarker()->enableRangeSat(enable);

	ui.sldMaxSaturation->setEnabled(enable);
	ui.sldMinSaturation->setEnabled(enable);
}

void HDTrackingWindow::on_chkEnableVal_stateChanged(int enable)
{
	viewers[currentCameraIndex]->selectedMarker()->enableRangeVal(enable);

	ui.sldMinValue->setEnabled(enable);
	ui.sldMaxValue->setEnabled(enable);
}

/************************************************************************/
/* Sliders Slots.                                                       */
/************************************************************************/
void HDTrackingWindow::on_sldMinHue_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMinHue((float)ui.sldMinHue->value(), 
		ui.chkEnableHue->isEnabled());
}

void HDTrackingWindow::on_sldMaxHue_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMaxHue((float)ui.sldMaxHue->value(),
		ui.chkEnableHue->isEnabled());
}

void HDTrackingWindow::on_sldMinSaturation_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMinSaturation((float)ui.sldMinSaturation->value() / 255.0f, 
		ui.chkEnableSat->isEnabled());
}

void HDTrackingWindow::on_sldMaxSaturation_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMaxSaturation((float)ui.sldMaxSaturation->value() / 255.0f, 
		ui.chkEnableSat->isEnabled());
}

void HDTrackingWindow::on_sldMinValue_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMinValue((float)ui.sldMinValue->value() / 255.0f, 
		ui.chkEnableVal->isEnabled());
}

void HDTrackingWindow::on_sldMaxValue_sliderMoved(int)
{
	viewers[currentCameraIndex]->selectedMarker()->setMaxValue((float)ui.sldMaxValue->value() / 255.0f,
		ui.chkEnableVal->isEnabled());
}

/************************************************************************/
/* Keyboard Handlers.													*/
/************************************************************************/
void HDTrackingWindow::keyPressEvent(QKeyEvent *event)
{
	if(controllers.count() > 0)
	{
		switch(event->key())
		{
		case Qt::Key_F:
			controllers[0]->setThumbPressed(true);
			break;

		case Qt::Key_D:
			controllers[0]->setIndexPressed(true);
			break;

		case Qt::Key_S:
			controllers[0]->setMiddlePressed(true);
			break;

		case Qt::Key_A:
			controllers[0]->setRingPressed(true);
			break;
		}
	}
}

void HDTrackingWindow::keyReleaseEvent(QKeyEvent * event)
{
	if(controllers.count() > 0)
	{
		switch(event->key())
		{
		case Qt::Key_F:
			controllers[0]->setThumbPressed(false);
			break;
		
		case Qt::Key_D:
			controllers[0]->setIndexPressed(false);
			break;

		case Qt::Key_S:
			controllers[0]->setMiddlePressed(false);
			break;

		case Qt::Key_A:
			controllers[0]->setRingPressed(false);
			break;
		}
	}
}
/************************************************************************/
/* Hardware Buttons Slots.                                              */
/************************************************************************/
void HDTrackingWindow::on_pushButtons_LeftThumbToggled(bool pressed)
{
	controllers[0]->setThumbPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("LeftThumb") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("LeftThumb") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_RightThumbToggled(bool pressed)
{
	controllers[1]->setThumbPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("RightThumb") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("RightThumb") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_LeftIndexToggled(bool pressed)
{
	controllers[0]->setIndexPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("LeftIndex") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("LeftIndex") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_RightIndexToggled(bool pressed)
{
	controllers[1]->setIndexPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("RightIndex") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("RightIndex") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_LeftMiddleToggled(bool pressed)
{
	controllers[0]->setMiddlePressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("LeftMiddle") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("LeftMiddle") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_RightMiddleToggled(bool pressed)
{
	controllers[1]->setMiddlePressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("RightMiddle") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("RightMiddle") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_LeftRingToggled(bool pressed)
{
	controllers[0]->setRingPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("LeftRing") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("LeftRing") + QString(" is Released"));
}

void HDTrackingWindow::on_pushButtons_RightRingToggled(bool pressed)
{
	controllers[1]->setRingPressed(pressed);

	if(pressed)
		QMessageBox::information(0, "Push Buttons Events", QString("RightRing") + QString(" is Pressed"));
	else
		QMessageBox::information(0, "Push Buttons Events", QString("RightRing") + QString(" is Released"));
}
